Apollo-client中的本地数据管理方法. 和远程数据的流动方向一样, 但是在到达 server之前会被 apollo-link-state 截获,并做处理.数据仍然保持单向流动.
调用withClientState
方法,并使用 resolver做对应的处理.
1 | import { withClientState } from 'apollo-link-state'; |
在 Apollo-client 上挂载 state,state link 应该在在链的末端,由此其他的 link 可以做逻辑上的处理, 但是必须要在 HttpLink之前
,只有这样本地的操作才可以在到达网络之前被截获. 如果使用了持久化查询(persisted queries), 也必须要在apollo-link-persisted-queries
之前.
1 | const client = new ApolloClient({ |
请求远程数据和本地数据,通过@client
指令来区分.
1 | const UPDATE_NETWORK_STATUS = gql` |
在组件注入 query 或者 mutate 就可以了
1 | const WrappedComponent = graphql(UPDATE_NETWORK_STATUS, { |
如果要从其他组件访问 nework status 怎么办? 因为在访问之前,并不知道是否有UPDATA_NETWORK_STATUS
存在,为了防止出现 undefined,需要提供一个默认的 state 作为初始值.
1 | const stateLink = withClientState({ |
组件查询 network也使用@client
指令
1 | const GET_ARTICLES = gql` |
Defaults
1 | const defaults = { |
Resolvers
resolvers 是实现 local state 的地方. resolver的 map是对应每个 GraphQL 对象类型的resolver 函数.
apollo-link-state
有四个重要的部分
- cache在上下文中,可以用来读取数据
- resolver 应该返回一个有
_typename
属性的对象, 也可以用dataIdFromObject
代替. 目的是 Apollo 用于数据的normalize - 如果需要执行异步操作,可以使用 promise.
- Query只针对 cache. 如果在所有的 mutate 之前执行 query,需要提供默认值
Default resolvers
不一定要为每个字段都建立特定的 resolvers,如果从 parent 对象返回的值和children 请求的字段一致,就不需要 resolvers.这就是default resovlers
1 |
|
Resolvers signature
Apollo-client 中的resolver 函数和用graph-tools
构建的 server 中的 resolvers 是完全一样的.
1 | fieldName:(obj,args,context,info)=>result; |
obj
: 包含 parent 字段 或者ROOT_QUERY
对象args
: 传递进入的参数, 例如updataNetworkStatus(isConnected:true)
,args
对象就是{isConnected:true}
context
: 在所有的link 中共享的数据. 重要的的一点是Apollo cache添加在其中,所以可以用cache.writeData({})
.如果想设定额外的值,可以在组件内设定,或者使用apollo-link-context
.info
: 有关 state 执行状态的信息. 个人不会用到
Async resolvers
如果想访问 REST 数据,可以参考apollo-link-rest
.
对于 RN或者 其他的 browser API,需要在组件的生命周期方法中添加触发函数.
这一部分暂时不写
Organizing resolvers
使用鸭子类型 ,每个feature都有自己的一套方法,然后合并起来
1 | import merge from 'lodash.merge'; |
可以设定默认值
1 | const currentUser = { |
updating the cache
可以通过context
访问或者更新 cache. Apollo cache API 有几个方法
writeData
直接在 Cahce 中写入数据,不用通过 query.
1 | const filter = { |
如果传递id属性,也可以在已经存在的对象中写入片段数据.
这里的id
应该对应对象的 cache key. 如果使用InMemroyCache
,并且没有覆盖dataObjectFromId
,cache key就是_typename:id
1 | const user = { |
writeQuery 和 readQuery
在某些情况下,写入到 cache 的数据依赖于已经存在的数据,例如 ,在 list 中添加一条 item或者对属性做修改. 做法是使用cache.readQuery
传递 query,在写入数据之前从 cache 中读取数据. 看看 list的例子
1 | let nextTodoId = 0; |
为了在 list 中添加 todo, 需要当前的 todos, 可以通过cache.readQuery
获取.
为了写入数据到 cache.可以使用cache.writeQuery
,cache.writeData
. 不同点在于cache.writeQuery
需要传递 query,来验证 data的结构. 在底层,cache.write
自动从data
构建了 query.
writeFragment 和 readFragment
cache.writeFragment
,在有了 cache key 情况下, 可以灵活的读取数据.
1 | const todos = { |
@client directive
Combining local and remote data
下面的例子中,我们从 server 获取到 username,从 apollo cache 获取到 cart 信息.两者在结果中融合在一起
1 | const getUser = gql` |